#include "Model.h"
#include <glm/glm.hpp>



Model::Model () : _needUpdate (false)
{

}

Model::Model (int vertexCount) : _needUpdate (false), _vertices (vertexCount),
		_normals (vertexCount), _texCoords (vertexCount) {}



Model::~Model ()
{

}



const QVector< glm::vec3 > & Model::getVertices () const
{
	return _vertices;
}



const QVector< glm::uvec3 > & Model::getFaces () const
{
	return _faces;
}



const QVector< glm::vec3 > & Model::getNormals ()
{
	update ();
	return _normals;
}



int Model::getVertexCount () const
{
	return _vertices.size ();
}



int Model::getFaceCount () const
{
	return _faces.size ();
}



// void Model::render () const
// {
// 	glEnableClientState (GL_VERTEX_ARRAY);
// 	glEnableClientState (GL_NORMAL_ARRAY);
// 	glVertexPointer (3, GL_FLOAT, 0, _vertices.data ());
// 	glNormalPointer (GL_FLOAT, 0, _normals.data ());
// 	glDrawElements (GL_TRIANGLES, getFaceCount (), GL_UNSIGNED_INT, _faces.data ());
// 	glDisableClientState (GL_VERTEX_ARRAY);
// 	glDisableClientState (GL_NORMAL_ARRAY);
// }



void Model::calcNormals ()
{
	_normals.clear ();
	_normals.resize (_vertices.size ());
	for (int i = 0; i < getFaceCount (); ++i) {
		glm::vec3 v1 = _vertices[_faces[i][1]] - _vertices[_faces[i][0]];
		glm::vec3 v2 = _vertices[_faces[i][2]] - _vertices[_faces[i][1]];
		glm::vec3 n = glm::normalize (glm::cross (v1, v2));
		for (int j = 0; j < 3; ++j)
			_normals[_faces[i][j]] += n;
	}
	for (size_t i = 0; i < _normals.size (); ++i)
		_normals[i] = glm::normalize (_normals[i]);
}

Model::BoundingBox Model::getBoundingBox () const
{
	BoundingBox boundingBox;
	memcpy (&boundingBox, &_vertices[0], sizeof (float) * 6);
	for (int i = 0; i < _vertices.size (); ++i) {
		for (int j = 0; j < 3; ++j) {
			if (_vertices[i][j] < boundingBox.minPoint[j])
				boundingBox.minPoint[j] = _vertices[i][j];
			else if (_vertices[i][j] > boundingBox.maxPoint[j])
				boundingBox.maxPoint[j] = _vertices[i][j];
		}
	}
	return boundingBox;
}

void Model::addVertex (const glm::vec3 & vertex)
{
	_vertices.push_back (vertex);
	_needUpdate = true;
}

void Model::addVertex (const glm::vec3 & vertex, const glm::vec2 &texCoord)
{
	_vertices.push_back (vertex);
	_texCoords.push_back (texCoord);
	_needUpdate = true;
}

void Model::setVertex (int index, const glm::vec3 & vertex)
{
	_vertices[index] = vertex;
	_needUpdate = true;
}

void Model::addFace (const glm::uvec3 & face)
{
	_faces.push_back (face);
	_needUpdate = true;
}

void Model::setFace (int index, const glm::uvec3 & face)
{
	_faces[index] = face;
	_needUpdate = true;
}

void Model::update ()
{
	if (_needUpdate) {
		calcNormals ();
		_needUpdate = false;
	}
}

void Model::addTexCoords (const glm::vec2 & texCoord)
{
	_texCoords.push_back (texCoord);
}

void Model::setTexCoord (int index, const glm::vec2 & texCoord)
{
	_texCoords[index] = texCoord;
}

const QVector< glm::vec2 > & Model::getTexCoords () const
{
	return _texCoords;
}

void Model::clearFace ()
{
	_faces.clear ();
}

QDataStream & operator>> (QDataStream & inStream, Model & model)
{
	// Read Vertices, Normals, TexCoords
	qint32 vertexNumber;
	inStream >> vertexNumber;
	model._vertices.resize (vertexNumber);
	model._normals.resize (vertexNumber);
	model._texCoords.resize (vertexNumber);
	for (int i = 0; i < vertexNumber; ++i) {
		inStream >> model._vertices[i][0] >> model._vertices[i][1] >> 
				model._vertices[i][2];
		inStream >> model._normals[i][0] >> model._normals[i][1] >> 
				model._normals[i][2];
		inStream >> model._texCoords[i][0] >> model._texCoords[i][1];
	}

	// Read Faces
	qint32 faceNumber;
	inStream >> faceNumber;
	model._faces.resize (faceNumber);
	for (int i = 0; i < faceNumber; ++i) {
		inStream >> model._faces[i][0] >> model._faces[i][1] >>
				model._faces[i][2];
	}
	model._needUpdate = false;
	return inStream;
}

QDataStream & operator<< (QDataStream & outStream, Model & model)
{
	if (model._needUpdate)
		model.update ();

	// Write Vertices, Normals, TexCoords
	qint32 vertexNumber = model._vertices.size ();
	outStream << vertexNumber;
	for (int i = 0; i < vertexNumber; ++i) {
		outStream << model._vertices[i][0] << model._vertices[i][1] << 
				model._vertices[i][2];
		outStream << model._normals[i][0] << model._normals[i][1] << 
				model._normals[i][2];
		outStream << model._texCoords[i][0] << model._texCoords[i][1];
	}

	// Write Faces
	qint32 faceNumber = model._faces.size ();
	outStream << faceNumber;
	for (int i = 0; i < faceNumber; ++i) {
		outStream << model._faces[i][0] << model._faces[i][1] <<
				model._faces[i][2];
	}
	return outStream;
}
